#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/of_address.h>
#include <linux/types.h>//消除ssize_t
#include <linux/platform_device.h> //platform 平台设备相关的头文件


#define led_dr   (*(volatile unsigned int *)((char*)led_addr + 0x00))
#define led_ddr  (*(volatile unsigned int *)((char*)led_addr + 0x04))
#define beep_dr  (*(volatile unsigned int *)((char*)beep_addr + 0x00))
#define beep_ddr (*(volatile unsigned int *)((char*)beep_addr + 0x04))
struct device_node *test_dev;//描述一个节点
struct property *test_property;//属性信息
int size;
unsigned int num[4] = {0};
const char * ptr;
unsigned int *led_addr  = NULL;
unsigned int *beep_addr = NULL;
ssize_t misc_read(struct file *fp,char __user *buf,size_t len,loff_t *off)
{
    return len;
}
ssize_t misc_write(struct file *fp,const char __user *buf,size_t len,loff_t *off )
{
    if(*buf == '1')
    {
        led_dr |= 1<<12;
        beep_dr |= 1<<22;
    }
    if (*buf == '0')
    {
        led_dr &= ~(1<<12);
        beep_dr &= ~(1<<22);
    }
    
    return len;
}
int misc_open(struct inode *no,struct file *fp)
{
    printk("open\n");
    return 0;
}
int misc_release(struct inode *no,struct file *fp)
{
    printk("release \n");
    return 0;
}
struct file_operations misc_fops = {
    .open = misc_open,
    .release = misc_release,
    .read = misc_read,
    .write = misc_write,
};
struct miscdevice misc_dev = {
    .name = "test_misc",
    .fops = &misc_fops,
};
static int test_init(void)
{
    int ret = 0;
    int i = 0;
    printk("hello test\n");
    test_dev = of_find_node_by_path("/test");
    if(test_dev == NULL)
    {
        printk("of_find_node_by_path id error\n");
        return -1;
    }
    printk("test_dev name is %s\n",test_dev->name);
    /**********获取 compatible 属性内容的代码************************************/
    test_property = of_find_property(test_dev,"compatible",&size);
    if(test_property == NULL)
    {
        printk("of_find_property is error \n");
        return -1;
    }
    printk("of_find_property compatible key %s   of_find_property compatible value %s \n",test_property->name,(char*)test_property->value);
    /**********获取 reg 属性内容的代码********************************************/
    ret = of_property_read_u32_array(test_dev,"reg",num,4);
    if(ret < 0)
    {
        printk("of_property_read_u32_array IS ERROR\n");
        return -1;
    }
    for ( i = 0; i < 4; i++)
    {

        printk("num[%d] = 0x%8x\n",i,num[i]);
    }
    /**********获取 status 属性内容的代码********************************************/
   ret = of_property_read_string(test_dev,"status",&ptr);
   if(ret < 0)
   {
        printk("of_proerty_read_string is error \n");
        return -1;
   }
   printk("stutas is %s\n",ptr);
   /**********misc redister*******************************************/
   ret = misc_register(&misc_dev);
    if(ret < 0)
    {
        printk("misc_register is error\n");
    }
    printk("misc_register is succuful \n");
    /******************ioremap***********************************/
    led_addr = of_iomap(test_dev,0);
    //led_addr = ioremap(0xff720000,8);
    if(led_addr == NULL)
    {
        printk("led_addr of_iomap is error\n");
   //     return -1;
    }
    //beep_addr = of_iomap(test_dev,1);
    beep_addr = ioremap(num[3],8);
    if(beep_addr == NULL)
    {
        printk("beep_addr of_iomap is error\n");
   //     return -1;
    }
    led_ddr |= 1<<12;
    beep_ddr |= 1<<22;
    led_dr |= 1<<12;
    return 0;
}
static void test_exit(void)
{
    misc_deregister(&misc_dev);
    printk("bye test\n");
    // iounmap(led_addr);
     iounmap(beep_addr);
}
MODULE_LICENSE("GPL");
module_init(test_init);
module_exit(test_exit);